package com.cqhfan.contentservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqhfan.api.clients.interaction.LikedRecordClient;
import com.cqhfan.api.clients.user.FollowClient;
import com.cqhfan.api.clients.user.UserClient;
import com.cqhfan.cache.annotations.MultiLevelCache;
import com.cqhfan.contentservice.mapper.WorksMapper;
import com.cqhfan.contentservice.service.WorksContentService;
import com.cqhfan.contentservice.service.WorksService;
import com.cqhfan.contentservice.service.WorksViewMemberService;
import com.cqhfan.core.domain.dto.PageDTO;
import com.cqhfan.core.domain.query.PageQuery;
import com.cqhfan.core.exceptions.BizException;
import com.cqhfan.core.utils.UserContext;
import com.cqhfan.pojo.content.dto.AddWorksDTO;
import com.cqhfan.pojo.content.po.Works;
import com.cqhfan.pojo.content.po.WorksContent;
import com.cqhfan.pojo.content.po.WorksViewMember;
import com.cqhfan.pojo.content.query.NearWorksQuery;
import com.cqhfan.pojo.content.query.ProfileWorksQuery;
import com.cqhfan.pojo.content.vo.ProfileWorksVO;
import com.cqhfan.pojo.content.vo.WorksVO;
import com.cqhfan.core.enums.WatchTypeEnum;
import com.cqhfan.pojo.user.po.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 眭传洪
 * @create 2025-08-01 0:38
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorksServiceImpl extends ServiceImpl<WorksMapper, Works> implements WorksService {

    private final WorksContentService worksContentService;

    private final WorksViewMemberService worksViewMemberService;

    private final FollowClient followClient;

    private final UserClient userClient;

    private final LikedRecordClient likedRecordClient;

    @Override
    @Transactional
    public void addWorks(AddWorksDTO body) {
        List<String> contents = body.getContents();
        if (CollUtil.isEmpty(contents)) {
            throw new BizException("作品内容为空");
        }
        Long userId = UserContext.getUser();
        // 设置并写入作品信息
        Works works = new Works();
        works.setTitle(body.getTitle());
        works.setDescription(body.getDescription());
        works.setAllowCommentType(body.getAllowCommentTypeEnum());
        works.setAllowForwardType(body.getAllowForwardTypeEnum());
        works.setWatchType(body.getWatchType());
        works.setTopic(body.getTopic());
        works.setAuthor(userId);
        works.setCover(body.getCover());
        works.setBrowseCount(0L);
        works.setIfSHow(Boolean.TRUE);
        works.setCollectQuantity(0);
        works.setCommentQuantity(0);
        works.setForwardQuantity(0);
        works.setLikeQuantity(0);
        works.setPublishTime(LocalDateTime.now());
        save(works);

        // 写入作品内容数据
        Long worksId = works.getId();
        List<WorksContent> worksContents = contents.stream()
                .map(item -> WorksContent.builder().worksId(worksId).contentUrl(item).build())
                .toList();
        worksContentService.saveBatch(worksContents);

        // 写入可以查看的用户ids
        WatchTypeEnum watchType = body.getWatchType();
        if (watchType != WatchTypeEnum.ANY) {
            return;
        }
        List<Long> canViewUserIds = body.getCanViewUserIds();
        if (CollUtil.isEmpty(contents)) {
            throw new BizException("可查看用户信息为空");
        }
        List<WorksViewMember> worksViewMembers = canViewUserIds.stream()
                .map(item -> WorksViewMember.builder().worksId(worksId).userId(item).build())
                .toList();
        worksViewMemberService.saveBatch(worksViewMembers);
    }

    @Override
    public PageDTO<WorksVO> pageByRecommend(PageQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();
        Long userId = UserContext.getUser();
        // 获取我的朋友
        List<Long> friendUserIds = followClient.listFriend(userId);

        // 查出非自己，非私有，非自己不能查看的视频，暂时直接按照发布时间降序排列
        Page<Works> page = getBaseMapper().selectRecommendFallPage(new Page<>(pageNum, pageSize), friendUserIds, userId);
        List<Works> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }

        // 构建并返回结果
        List<WorksVO> result = buildWorksVO(records);
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }

    @Override
    public PageDTO<WorksVO> pageByFollow(PageQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();
        Long userId = UserContext.getUser();

        // 获取我关注的人和朋友
        List<Long> followUserIds = followClient.listByUserId(userId);
        if (CollUtil.isEmpty(followUserIds)) {
            // 没有关注的人直接返回空列表
            return PageDTO.empty();
        }
        List<Long> friendUserIds = followClient.listFriend(userId);

        // 查询出作品信息
        Page<Works> page = getBaseMapper().selectFollowFallPage(new Page<>(pageNum, pageSize),
                friendUserIds, followUserIds, userId);
        List<Works> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }

        // 构建vo
        List<WorksVO> result = buildWorksVO(records);
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }

    @Override
    public PageDTO<WorksVO> pageByFriend(PageQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();
        Long userId = UserContext.getUser();

        // 获取我关注的人和朋友
        List<Long> friendUserIds = followClient.listFriend(userId);
        if (CollUtil.isEmpty(friendUserIds)) {
            // 没有朋友直接返回空列表
            return PageDTO.empty();
        }

        // 查询出作品信息
        Page<Works> page = getBaseMapper().selectFriendFallPage(new Page<>(pageNum, pageSize), friendUserIds, userId);
        List<Works> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }

        // 构建vo
        List<WorksVO> result = buildWorksVO(records);
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }

    @Override
    public PageDTO<WorksVO> pageByNear(NearWorksQuery query) {
        return null;
    }

    @Override
    public PageDTO<WorksVO> pageByRecommendForGuest(PageQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();

        // 降序查询数据库
        Page<Works> page = lambdaQuery().orderByDesc(Works::getPublishTime).page(new Page<>(pageNum, pageSize));
        List<Works> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }

        // 构建vo
        List<WorksVO> result = buildWorksVO(records);
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }

    private List<WorksVO> buildWorksVO(List<Works> records) {
        // 获取作品用户信息
        List<Long> userIds = records.stream().map(Works::getAuthor).toList();
        List<User> users = userClient.listByIds(userIds);
        if (CollUtil.isEmpty(users)) {
            throw new BizException("用户信息获取失败");
        }
        Map<Long, User> userMap = users.stream().collect(Collectors.toMap(User::getId, u -> u));

        // 获取作品的内容信息
        Set<Long> worksIds = records.stream().map(Works::getId).collect(Collectors.toSet());
        List<WorksContent> contents = worksContentService.lambdaQuery().in(WorksContent::getWorksId, worksIds).list();
        if (CollUtil.isEmpty(contents)) {
            throw new BizException("作品内容信息为空");
        }
        Map<Long, List<String>> contentMap = contents.stream()
                .collect(Collectors.groupingBy(WorksContent::getWorksId,
                        Collectors.mapping(WorksContent::getContentUrl, Collectors.toList())
                ));

        // 查询点赞情况
        Set<Long> likedIds = likedRecordClient.listLikeStatus(worksIds);

        // 转换vo
        List<WorksVO> result = new ArrayList<>(records.size());
        for (Works works : records) {
            Long worksId = works.getId();
            Long author = works.getAuthor();
            User user = userMap.get(author);
            if (user == null) {
                continue;
            }
            WorksVO item = BeanUtil.toBean(works, WorksVO.class);
            item.setAvatar(user.getAvatar());
            item.setNickName(user.getNickName());
            item.setWorksContents(contentMap.get(worksId));
            item.setIfLiked(likedIds.contains(worksId));
            result.add(item);
        }
        return result;
    }

    @Override
    public PageDTO<ProfileWorksVO> pageByUserId(ProfileWorksQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();
        Long viewUserId = query.getViewUserId();
        boolean isSelf = false;
        if (viewUserId == null) {
            // 未传userId代表查看的是自己的页面
            viewUserId = UserContext.getUser();
            isSelf = true;
        }

        // 查询作品信息
        Page<Works> page;
        if (isSelf) {
            // 是自己的，直接按照发布时间降序
            page = lambdaQuery()
                    .eq(Works::getAuthor, viewUserId)
                    .eq(Works::getIfSHow, true)
                    .orderByDesc(Works::getPublishTime)
                    .page(new Page<>(pageNum, pageSize));
        } else {
            // 查看的是其他人的页面 需要先拿到朋友信息，然后再根据类似查询好友
            List<Long> viewUserFriendsUserIds = followClient.listFriend(viewUserId);
            Long myUserId = UserContext.getUser();
            if (!viewUserFriendsUserIds.contains(myUserId)) {
                // 我不是他的朋友，只查询他公开的 因为朋友能见的肯定不能看到，然后部分的前提是你们也是朋友
                page = lambdaQuery()
                        .eq(Works::getAuthor, viewUserId)
                        .eq(Works::getIfSHow, true)
                        .eq(Works::getWatchType, WatchTypeEnum.ALL.getValue())
                        .orderByDesc(Works::getPublishTime)
                        .page(new Page<>(pageNum, pageSize));
            } else {
                // 这里查询的是我是他的朋友，则需要判断 我在不在他允许的序列里
                page = getBaseMapper().selectProfileWorksPage(new Page<>(pageNum, pageSize), myUserId, viewUserId);
            }
        }

        List<Works> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }
        // 转换vo
        List<ProfileWorksVO> result = records.stream().map(item -> {
            ProfileWorksVO vo = new ProfileWorksVO();
            vo.setId(item.getId());
            vo.setCover(item.getCover());
            vo.setLikedNumber(item.getLikeQuantity());
            return vo;
        }).toList();
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }

    @Override
    public WorksVO viewWorks(Long worksId) {
        // 获取作品信息
        Works works = getById(worksId);
        if (works == null) {
            throw new BizException("没有该作品信息");
        }

        // 查询对应的用户信息
        List<User> users = userClient.listByIds(Collections.singletonList(works.getAuthor()));
        if (CollUtil.isEmpty(users)) {
            throw new BizException("作品用户信息获取失败");
        }
        User user = users.get(0);

        // 获取内容信息
        List<WorksContent> contents = worksContentService.lambdaQuery()
                .eq(WorksContent::getWorksId, worksId)
                .list();

        // 封装数据
        WorksVO result = BeanUtil.toBean(works, WorksVO.class);
        result.setNickName(user.getNickName());
        result.setAvatar(user.getAvatar());
        result.setWorksContents(contents.stream().map(WorksContent::getContentUrl).toList());
        return result;
    }

    @Override
    @MultiLevelCache(key = "#worksId", prefix = "works:id")
    public Works getByWorksId(Long worksId) {
        return getById(worksId);
    }
}
